#pragma once

#include <iostream>
#include "Mythread.hpp"
#include <vector>
#include <queue>
#include <pthread.h>
#include <functional>
#include <memory>
#include <unistd.h>
#include "Log.hpp"

const static int gdefaultthreadnum = 3;

using task_t = std::function<void()>;

template <class T>
class threadpool_t
{
private:
	void LockQueue()
	{
		pthread_mutex_lock(&_mutex);
	}

	void UnLockQueue()
	{
		pthread_mutex_unlock(&_mutex);
	}

	void ThreadSleep()
	{
		pthread_cond_wait(&_cond, &_mutex);
	}

	void ThreadWakeUp()
	{
		pthread_cond_signal(&_cond);
	}

	void ThreadWakeupAll()
	{
		pthread_cond_broadcast(&_cond);
	}

	threadpool_t(int threadnum = gdefaultthreadnum) : _threadnum(threadnum), _threadwaitnum(0), _isrunning(false)
	{
		pthread_mutex_init(&_mutex, nullptr);
		pthread_cond_init(&_cond, nullptr);
		LOG(INFO, "ThreadPool Construct()");
	}
	void HandlerTask(std::string name)
	{
		LOG(INFO, "%s is running...", name.c_str());
		while (true)
		{
			// 保证队列安全
			LockQueue();
			// 2队列中不一定有任务
			while (_task_queue.empty() && _isrunning)
			{
				_threadwaitnum++;
				ThreadSleep();
				_threadwaitnum--;
			}
			// 2.1如果线程池已经退出了 && 任务队列是空的
			if (_task_queue.empty() && !_isrunning)
			{
				UnLockQueue();
				std::cout << name << " quit..." << std::endl;
				sleep(1);
				break;
			}
			// 2.2如果线程池不退出&&任务队列不为空
			// 2.3如果线程池已经退出&&任务队列不为空的 -- 处理完所有任务后才退出
			// 3.一定有任务，处理任务

			T t = _task_queue.front();
			_task_queue.pop();

			UnLockQueue();
			LOG(DEBUG, "%s get a task", name.c_str());
			// 处理任务
			t();
			// std::cout << name << ":" << t << std::endl;
			// LOG(DEBUG, "%s handler a task, result is: %s", name.c_str(), t.ResultToString().c_str());
			
		}
	}
	void InitThreadPool()
	{
		// 先构建线程，不启动
		for (int i = 0; i < _threadnum; i++)
		{
			std::string name = "thread-" + std::to_string(i + 1);
			_threads.emplace_back(std::bind(&threadpool_t::HandlerTask, this, std::placeholders::_1), name);
			// bing绑定this就是默认会传的参数，在HandlerTask函数参数中不记
			LOG(INFO, "init thread %s done", name.c_str());
		}

		_isrunning = true; // 不能放Start里面是因为有些线程都已经启动在跑了，但_isrunning都还没被设置，会出现线程退出
	}

	void Start()
	{
		for (auto &thread : _threads)
		{
			thread.start();
		}
	}

public:
	static threadpool_t<T> *GetInstance()
	{
		// 只有第一次会创建对象，后续都是获取
		// 双判断的方式，可以有效减少获取单例的加锁成本，而且保证线程安全
		// 如果没有二次判断，在其他线程获取单例的时候，会进行加锁，会出现bug
		LockGuard lockGguard(&_lock); // 保证第二次之后，所有线程，不用在加锁，直接返回_instance单例对象
		if (_instance == nullptr)
		{
			_instance = new threadpool_t<T>();
			_instance->InitThreadPool();
			_instance->Start();
			LOG(DEBUG, "创建线程池单例");
			return _instance;
		}

		LOG(DEBUG, "获取线程池单例");
		return _instance;
	}

	void Stop()
	{
		LockQueue();
		_isrunning = false;
		ThreadWakeupAll(); // 唤醒全部进程进行退出或处理完任务再退出
		UnLockQueue();
	}

	void Wait()
	{
		for (auto &thread : _threads)
		{
			thread.join();
			LOG(INFO, "%s is quit...", thread.name().c_str());
		}
		// std::cout << "Wait success..." << std::endl;
	}

	bool Enqueue(const T &t) // 加入任务	fix!!
	{
		bool ret = false;
		LockQueue();
		if (_isrunning)
		{
			_task_queue.push(t);
			if (_threadwaitnum > 0)
			{
				ThreadWakeUp();
			}

			LOG(DEBUG, "enqueue task success");
			ret = true;
		}
		UnLockQueue();

		return ret;
	}
	~threadpool_t()
	{
		pthread_mutex_destroy(&_mutex);
		pthread_cond_destroy(&_cond);
	}

private:
	int _threadnum; // 线程数
	std::vector<Mythread::Thread> _threads;
	std::queue<T> _task_queue; // 任务队列

	pthread_mutex_t _mutex;
	pthread_cond_t _cond;

	int _threadwaitnum;
	bool _isrunning;

	// 添加单例模式
	static threadpool_t<T> *_instance;
	static pthread_mutex_t _lock;
};

template <typename T>
threadpool_t<T> *threadpool_t<T>::_instance = nullptr;

template <typename T>
pthread_mutex_t threadpool_t<T>::_lock = PTHREAD_MUTEX_INITIALIZER;